package web.common.internal.core.security;

import web.common.core.security.PasswordEncoder;
import web.common.core.security.PasswordEncoderType;
import web.common.core.util.AssertUtil;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Jin Zheng
 * @since 2022-01-19
 */
public class PasswordEncoderFacade implements PasswordEncoder {
	private static final int RANDOM_LENGTH = 6;
	private final PasswordEncoderType defaultType;
	private final Map<PasswordEncoderType, PasswordEncoder> encoderMap = new HashMap<>();

	public PasswordEncoderFacade(PasswordEncoderType type) {
		AssertUtil.notNull(type, "PasswordEncoderType");
		this.defaultType = type;
		this.init();
	}

	private void init() {
		encoderMap.put(PasswordEncoderType.NOOP, new NoopPasswordEncoder());
		encoderMap.put(PasswordEncoderType.MD5, new DigestPasswordEncoder(PasswordEncoderType.MD5, RANDOM_LENGTH));
		encoderMap.put(PasswordEncoderType.SHA1, new DigestPasswordEncoder(PasswordEncoderType.SHA1, RANDOM_LENGTH));
		encoderMap.put(PasswordEncoderType.SHA256, new DigestPasswordEncoder(PasswordEncoderType.SHA256, RANDOM_LENGTH));
		encoderMap.put(PasswordEncoderType.SHA384, new DigestPasswordEncoder(PasswordEncoderType.SHA384, RANDOM_LENGTH));
		encoderMap.put(PasswordEncoderType.SHA512, new DigestPasswordEncoder(PasswordEncoderType.SHA512, RANDOM_LENGTH));
	}

	@Override
	public String encode(String origin) {
		AssertUtil.notEmpty(origin, "原始密码");
		var encoder = this.getEncoder(defaultType);
		return encoder.encode(origin);
	}

	@Override
	public boolean matches(String origin, String encoded) {
		AssertUtil.notEmpty(origin, "原始密码");
		AssertUtil.notEmpty(encoded, "编码过的密码");
		var info = parseInfo(encoded);
		var encoder = this.getEncoder(info.getType());
		return encoder.matches(origin, encoded);
	}

	private PasswordEncoder getEncoder(PasswordEncoderType type) {
		var encoder = encoderMap.get(type);
		if (encoder == null) {
			throw new UnsupportedOperationException("未知类型: " + type);
		}
		return encoder;
	}

	public static PasswordEncoderInfo parseInfo(String encoded) {
		int startPos = encoded.indexOf(BRACE_START);
		int endPos = encoded.indexOf(BRACE_END);
		int randomPos = encoded.indexOf(RANDOM_SPLIT);
		if (startPos == -1 || endPos == -1) {
			throw new UnsupportedOperationException("编码密码格式错误");
		}
		var strType = encoded.substring(startPos + 1, endPos);
		var type = PasswordEncoderType.getType(strType);
		if (type == null) {
			throw new UnsupportedOperationException("未知类型: " + strType);
		}
		PasswordEncoderInfo info = new PasswordEncoderInfo();
		info.setType(type);
		if (randomPos != -1) {
			info.setRandom(encoded.substring(endPos + 1, randomPos));
			info.setEncoded(encoded.substring(randomPos + 1));
		} else {
			info.setRandom("");
			info.setEncoded(encoded.substring(endPos + 1));
		}
		return info;
	}

}
